package com.xone.collaboration.service.impl.process;

import com.google.common.collect.Lists;
import com.xone.collaboration.service.OperationProcess;
import com.xone.collaboration.service.vo.OperationResult;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

@Component
public class OperationProcessChain implements ApplicationContextAware,OperationProcess {

    @Autowired
    private ApplicationContext applicationContext;

    List<OperationProcess> processesChain = Lists.newArrayList();

    @PostConstruct
    public void init(){
        Map<String,OperationProcess> map =  applicationContext.getBeansOfType(OperationProcess.class);
        map.keySet().forEach(key->{
            OperationProcess process =  map.get(key);
            processesChain.add(process);
        });
        processesChain.remove(this.applicationContext.getBean(OperationProcessChain.class));

        processesChain.sort(new Comparator<OperationProcess>() {
            @Override
            public int compare(OperationProcess o1, OperationProcess o2) {
                Order order1 = o1.getClass().getAnnotation(Order.class);
                Order order2 = o2.getClass().getAnnotation(Order.class);
                return order1.value() - order2.value();
            }
        });
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public OperationResult process(OperationContext context) {
        for (OperationProcess process : processesChain) {
            if(process.needRun(context)){
                process.process(context);
            }
        }
        return OperationResult.of(context.success,context.message);
    }

    @Override
    public boolean needRun(OperationContext context) {
        return true;
    }
}
